<script id="vertex-shader" type="x-shader/x-vertex">
    precision mediump float;

    attribute vec4 vPosition;
    attribute vec4 vColor;
    varying vec4 fColor;
    uniform vec4 r;
    uniform mat4 scaleM;

    // quaternion multiplier
    vec4 multq(vec4 a, vec4 b) {
    return(vec4(a.x*b.x - dot(a.yzw, b.yzw), a.x*b.yzw+b.x*a.yzw+cross(b.yzw, a.yzw)));
    }

    // inverse quaternion
    vec4 invq(vec4 a) {
    return(vec4(a.x, -a.yzw)/dot(a,a));
    }

    void main() {
        vec4 p;
        p = vec4(0.0, vPosition.xyz);  // input point quaternion
        p = multq(r, multq(p, invq(r))); // rotated point quaternion
        gl_Position = scaleM * vec4(p.yzw, 1.0); // convert back to homogeneous coordinates
        fColor=vColor;
    }
</script>

<script id="fragment-shader" type="x-shader/x-fragment">
    precision mediump float;
    varying vec4 fColor;

    void main(){
        gl_FragColor=fColor;
    }
</script>
<script src="js/jquery-3.5.1.min.js"></script>
<script type="text/javascript" src="js/Common/webgl-utils.js"></script>
<script type="text/javascript" src="js/Common/initShaders.js"></script>
<script type="text/javascript" src="js/Common/MV.js"></script>
<script type="text/javascript" src="Experiment/Experiment2/snowman.js"></script>
<canvas id="gl-canvas" width="512" height="512">
    Oooooops!
</canvas>